package cn.kevinkun.LeanCloud;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.UsesPermissions;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.Component;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;
import com.google.appinventor.components.runtime.util.YailList;

import android.app.Activity;

@DesignerComponent(version = 20241014, category = ComponentCategory.EXTENSION, description = "http://www.kevinkun.cn/leancloud.html", iconName = "aiwebres/leancloud.svg", nonVisible = true)
@SimpleObject(external = true)
@UsesPermissions(permissionNames = "android.permission.INTERNET")
public class LeanLeaderboard extends AndroidNonvisibleComponent implements Component {

	String url = "";
	String appid = "";
	String appkey = "";
	String lbName = "";
	String apiversion = "1.1";
	Map<String, String> headers = new HashMap<String, String>();
	private final Activity activity;

	public LeanLeaderboard(ComponentContainer container) {
		super(container.$form());
		activity = container.$context();
	}

	@SimpleFunction(description = "")
	public void Init(String restApiUrl, String appId, String masterKey, String leaderboardName) {
		url = restApiUrl;
		appid = appId;
		appkey = masterKey;
		lbName = leaderboardName;

		headers.clear();
		headers.put("X-LC-Id", appid);
		headers.put("X-LC-Key", appkey + ",master");
		headers.put("Content-Type", "application/json");

	}

	@SimpleFunction(description = "userName only accept letters, numbers, and underscore_")
	public void SaveScore(String userName, float score) {
		String realUrl = url + "/" + apiversion + "/leaderboard/entities/" + userName + "/statistics";

		JSONArray jsonArray = new JSONArray();
		JSONObject jsonObject = new JSONObject();
		try {
			jsonObject.put("statisticName", lbName);
			jsonObject.put("statisticValue", score);
			jsonArray.put(jsonObject);
		} catch (JSONException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		byte[] body = jsonArray.toString().getBytes();

		HttpUtils.doHttpReqeust("POST", realUrl, headers, body, new HttpUtils.Callback() {

			@Override
			public void onSuccess(String result) {
				// TODO Auto-generated method stub

				activity.runOnUiThread(new Runnable() {
					public void run() {
						try {
							JSONObject object;
							object = new JSONObject(result);
							if (object.has("error")) {
								onError(object.getString("error"));
							} else {
								JSONArray results = object.getJSONArray("results");
								final double newscore = ((JSONObject) (results.get(0))).getDouble("statisticValue");
								StoredScore(userName, newscore);
							}
						} catch (JSONException e) {
							onError(e.getMessage());
						}
					}
				});
			}

			@Override
			public void onError(String error) {

				activity.runOnUiThread(new Runnable() {
					@Override
					public void run() {
						OnError(error);
					}
				});
			}
		});
	}

	@SimpleFunction(description = "")
	public void GetScore(String userName) {
		String realUrl = url + "/" + apiversion + "/leaderboard/entities/" + userName + "/statistics";

		realUrl = realUrl + "?statistics=" + lbName;

		HttpUtils.doHttpReqeust("GET", realUrl, headers, null, new HttpUtils.Callback() {

			@Override
			public void onSuccess(String result) {
				// TODO Auto-generated method stub
				activity.runOnUiThread(new Runnable() {
					public void run() {
						try {
							JSONObject object = new JSONObject(result);

							if (object.has("error")) {
								OnError(object.getString("error"));
							} else {
								JSONArray results = object.getJSONArray("results");
								if (result.length() > 0) {
									double score = results.getJSONObject(0).getDouble("statisticValue");
									String name = results.getJSONObject(0).getString("entity");
									GotScore(name, score);
								} else {
									OnError("No such user");
								}

							}
						} catch (JSONException e) {
							OnError(e.getMessage());

						}
					}
				});
			}

			@Override
			public void onError(String error) {
				// TODO Auto-generated method stub
				activity.runOnUiThread(new Runnable() {
					@Override
					public void run() {
						OnError(error);
					}
				});
			}
		});

	}

	@SimpleFunction(description = "")
	public void GetTopScores(int startPosition, int maxCount) {
		String realUrl = url + "/" + apiversion + "/leaderboard/leaderboards/entity/" + lbName + "/ranks";
		if (maxCount < 1) {
			maxCount = 20;
		}
		realUrl = realUrl + "?startPosition=" + (startPosition - 1) + "&maxResultsCount=" + maxCount;

		HttpUtils.doHttpReqeust("GET", realUrl, headers, null, new HttpUtils.Callback() {

			@Override
			public void onSuccess(String result) {
				// TODO Auto-generated method stub
				activity.runOnUiThread(new Runnable() {
					public void run() {
						try {
							JSONObject object = new JSONObject(result);

							if (object.has("error")) {
								OnError(object.getString("error"));
							} else {
								final List<Object> scores = new ArrayList<Object>();
								JSONArray results = object.getJSONArray("results");
								for (int i = 0; i < results.length(); i++) {
									List<Object> score = new ArrayList<Object>();
									JSONObject d = results.getJSONObject(i);

									score.add(d.getInt("rank") + 1);
									score.add(d.getString("entity"));
									score.add(d.getDouble("statisticValue"));

									scores.add(score);
								}

								GotTopScores(YailList.makeList(scores));

							}
						} catch (JSONException e) {
							OnError(e.getMessage());

						}
					}
				});
			}

			@Override
			public void onError(String error) {
				// TODO Auto-generated method stub
				activity.runOnUiThread(new Runnable() {
					@Override
					public void run() {
						OnError(error);
					}
				});
			}
		});

	}

	@SimpleFunction(description = "")
	public void GetNearbyScores(String userName, int maxCount) {
		String realUrl = url + "/" + apiversion + "/leaderboard/leaderboards/entity/" + lbName + "/ranks/" + userName;
		if (maxCount < 1) {
			maxCount = 20;
		}
		realUrl = realUrl + "?maxResultsCount=" + maxCount;

		HttpUtils.doHttpReqeust("GET", realUrl, headers, null, new HttpUtils.Callback() {

			@Override
			public void onSuccess(String result) {
				// TODO Auto-generated method stub
				activity.runOnUiThread(new Runnable() {
					public void run() {
						try {
							JSONObject object = new JSONObject(result);
							if (object.has("error")) {
								OnError(object.getString("error"));
							} else {
								final List<Object> scores = new ArrayList<Object>();
								JSONArray results = object.getJSONArray("results");
								for (int i = 0; i < results.length(); i++) {
									List<Object> score = new ArrayList<Object>();
									JSONObject d = results.getJSONObject(i);
									score.add(d.getInt("rank") + 1);
									score.add(d.getString("entity"));
									score.add(d.getDouble("statisticValue"));

									scores.add(score);
								}

								GotNearbyScores(YailList.makeList(scores));

							}
						} catch (JSONException e) {
							OnError(e.getMessage());

						}
					}
				});
			}

			@Override
			public void onError(String error) {
				// TODO Auto-generated method stub
				activity.runOnUiThread(new Runnable() {
					@Override
					public void run() {
						OnError(error);
					}
				});
			}
		});

	}

	@SimpleEvent
	public void OnError(String error) {
		EventDispatcher.dispatchEvent(this, "OnError", error);
	}

	@SimpleEvent
	public void StoredScore(String userName, double newScore) {
		EventDispatcher.dispatchEvent(this, "StoredScore", userName, newScore);
	}

	@SimpleEvent
	public void GotScore(String userName, double score) {
		EventDispatcher.dispatchEvent(this, "GotScore", userName, score);
	}

	@SimpleEvent
	public void GotTopScores(YailList topScores) {
		EventDispatcher.dispatchEvent(this, "GotTopScores", topScores);
	}

	@SimpleEvent
	public void GotNearbyScores(YailList nearbyScores) {
		EventDispatcher.dispatchEvent(this, "GotNearbyScores", nearbyScores);
	}

}
